<template>
<div>
  <div ref="carouselBox" class="carousel-box">
    <el-carousel
      ref="carousel"
      class="carousel-container"
      :autoplay="false"
      indicator-position="none"
      arrow="never"
      :loop="false"
      v-if="imageList.length > 0"
    >
      <el-carousel-item
        v-for="item in imageList"
        :key="item.id"
        :name="item.id"
      >
        <canvas :id="`canvas_${item.id}`" :width="canvasWidth" :height="canvasHeight"></canvas>
      </el-carousel-item>
    </el-carousel>
    <el-empty v-else description="暂无图片"></el-empty>
  </div>
  <!-- 缩略图 -->
  <el-scrollbar>
    <div class="scrollbar-flex-content">
      <div
        v-for="item in imageList"
        :key="item.id"
        :class="{
          'scrollbar-demo-item': true,
          'active': activeImageId === item.id
        }"
        :style="{ 'background-image': `url(${item.url})` }"
        @click="changeImage(item.id)"
      >
        <el-icon class="close-icon" @click.stop="delImage(item.id)"><Close /></el-icon>
      </div>
    </div>
  </el-scrollbar>
  
</div>
</template>
<script lang="ts" setup name="CanvasList">
import { Canvas, Path, FabricImage } from "fabric";
import { nextTick, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue';
import { calculateScaledSizeAndPosition, generatePathString, generateUUID, isTextValid } from "@/utils";

const { imageList, isAutoChoose } = defineProps<{ imageList: any[], isAutoChoose: boolean }>()

// 记录选中的文字
let selectedItem: string[] = []
// 记录所有图形实例
let pathList: any[] = []
// 记录所有画布实例
let canvasList: any[] = []

// 当前激活的图片id
const activeImageId = ref('')
// 轮播图实例
const carouselBox: any = ref(null)
const carousel: any = ref(null)
// 画布宽度
const canvasWidth = ref(672);
// 画布高度
const canvasHeight = ref(340);

// 监听父盒子大小变化
const updateCanvasSize = () => {
  if (!carouselBox.value) return;
  const parentWidth = carouselBox.value.clientWidth;
  const parentHeight = carouselBox.value.clientHeight;
  
  canvasWidth.value = parentWidth;
  canvasHeight.value = parentHeight;
  nextTick(() => {
    renderAllCanvas();
  })
};
// 绘制所有画布
const renderAllCanvas = () => {
  canvasList.forEach((item: any) => {
    const imageItem = imageList.find((imageItem: any) => imageItem.id === item.id)
    const { left, top, scaleRatio } = calculateScaledSizeAndPosition(imageItem.width, imageItem.height, canvasWidth.value, canvasHeight.value)
    item.canvas.clear();
    item.canvas.setWidth(canvasWidth.value);
    item.canvas.setHeight(canvasHeight.value);
    item.img.set({
      left,
      top,
      scaleX: scaleRatio,
      scaleY: scaleRatio,
    })
    item.canvas.add(item.img)
    const newPaths = item.pathList.map((path: any) => {
      const { fill, data } = path
      let newPath = new Path(generatePathString(imageItem.width, imageItem.height, data.text_box_position, canvasWidth.value, canvasHeight.value))
      newPath.set({
        fill,
        stroke: "black",
        strokeWidth: 1,
        opacity: 0.5,
        hasControls: false,
        hasBorders: false,
        lockMovementX: true,
        lockMovementY: true,
        hoverCursor: 'pointer',
        data,
      })
      pathList.filter((pathItem: any) => pathItem.get("data").pathId !== path.get("data").pathId)
      item.canvas.add(newPath)
      return newPath
    })
    item.pathList = newPaths
    pathList = pathList.concat(newPaths)
    item.canvas.renderAll();
  })
}

onMounted(() => {
  window.addEventListener('resize', updateCanvasSize);
  updateCanvasSize();
})
onBeforeUnmount(() => {
  window.removeEventListener('resize', updateCanvasSize);
})

const emit = defineEmits(['select', 'delImage'])
// 监听数据变化
watchEffect((onCleanup) => {
  const oldVal = JSON.parse(JSON.stringify(imageList)); // 深拷贝旧值
  onCleanup(() => {
    const newVal = imageList;
    // 新增的图片
    const newImage = newVal.filter((item: any) => 
      !oldVal.some((oldItem: any) => 
        oldItem.id === item.id))
    if(newImage.length > 0) {
      activeImageId.value = imageList[0].id
      nextTick(async () => {
        newImage.forEach(async (item: any) => {
          const { left, top, scaleRatio } = calculateScaledSizeAndPosition(item.width, item.height, canvasWidth.value, canvasHeight.value)
          let canvas = new Canvas(`canvas_${item.id}`, {
            selection: false,
          });
          const img = await FabricImage.fromURL(item.url)
          img.set({
            left,
            top,
            scaleX: scaleRatio,
            scaleY: scaleRatio,
            selectable: false,
            hasControls: false,
            hasBorders: false,
            lockMovementX: true,
            lockMovementY: true,
            hoverCursor: 'default',
          })
          canvas.add(img)
          // 监听鼠标点击
          canvas.on("mouse:down", (options: any) => {
            if(options.target?.type !== "path") return;
            const data = options.target.get("data");
            console.log(data);
            const index = selectedItem.indexOf(data.pathId);
            if(index === -1) {
              // 选中
              selectedItem.push(data.pathId);
              options.target.set({
                fill: "red",
              });
              emit('select', data.text, true)
            } else {
              // 取消选中
              options.target.set({
                fill: "transparent",
              });
              selectedItem.splice(index, 1);
              emit('select', data.text, false)
            }
            canvas.renderAll();
          });
          canvasList.push({
            id: item.id,
            canvas: canvas,
            img: img,
            pathList: [],
          })
        })
      })
    }
    // 新增的图片识别信息
    const newImageDatas = newVal.filter((item: any) => 
      item.recognizeResult !== null &&
      oldVal.find((oldItem: any) => 
        oldItem.id === item.id).recognizeResult === null)
    if(newImageDatas.length > 0) {
      newImageDatas.forEach((item: any) => {
        const canvasItem = canvasList.find((canvasItem: any) => canvasItem.id === item.id)
        let canvas = canvasItem.canvas;
        item.recognizeResult.data.forEach((dataItem: any) => {
          // 绘制识别框
          let customPath = new Path(generatePathString(item.width, item.height, dataItem.text_box_position, canvasWidth.value, canvasHeight.value));
          customPath.set({
            fill: "transparent",
            stroke: "black",
            strokeWidth: 1,
            opacity: 0.5,
            hasControls: false,
            hasBorders: false,
            lockMovementX: true,
            lockMovementY: true,
            hoverCursor: 'pointer',
            data: {
              ...dataItem,
              canvasId: `canvas_${item.id}`,
              pathId: `path_${generateUUID()}`,
            },
          })
          console.log(customPath);
          
          canvas.add(customPath)
          canvasItem.pathList.push(customPath)
          pathList.push(customPath)
        })
      })
    }
    // 自动选择符合的数字
    if(isAutoChoose) {
      pathList.forEach((path: any) => {
        const data = path.get("data");
        const isValid = isTextValid(data.text);
        if(!isValid) return;
        // 自动选择
        selectedItem.push(data.pathId);
        path.set({
          fill: "red",
        });
        emit('select', data.text, true)
      })
    }
  });
});

// 切换图片
const changeImage = (id: string) => {
  activeImageId.value = id;
  carousel.value?.setActiveItem(id);
}
// 删除图片
const delImage = (id: string) => {
  emit('delImage', id)
  canvasList = canvasList.filter((item: any) => item.id !== id)
  // 移除对应图形实例
  pathList = pathList.filter((item: any) => item.get("data").canvasId !== `canvas_${id}`)
  nextTick(() => {
    activeImageId.value = imageList[0]?.id;
  })
}
// 清空
const clearAll = () => {
  canvasList.forEach((item: any) => {
    item.canvas.clear();
    item.pathList = [];
  })
  canvasList = [];
  pathList = [];
  selectedItem = [];
  activeImageId.value = '';
}
defineExpose({
  clearAll
})
</script>
<style lang="less" scoped>
.carousel-box {
  width: 100%; /* 容器宽度 */
  height: auto; /* 高度自动 */
  position: relative; /* 相对定位 */
  overflow: hidden; /* 隐藏溢出部分 */
  aspect-ratio: 16 / 9; /* 设置宽高比 */
  :deep(.el-carousel) {
    height: 100%;
    .el-carousel__container {
      height: 100%;
    }
  }
  .carousel-item {
    height: 100%;
  }
}
.scrollbar-flex-content {
  display: flex;
  .scrollbar-demo-item {
    position: relative;
    box-sizing: border-box;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100px;
    height: 50px;
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    margin: 10px;
    text-align: center;
    border-radius: 4px;
    cursor: pointer;
    &.active {
      border: 1px solid var(--el-color-danger);
      .close-icon {
        display: block;
      }
    }
    .close-icon {
      display: none;
      position: absolute;
      top: -8px;
      right: -16px;
      color: var(--el-color-danger);
      font-size: 18px;
    }
  }
}
</style>